#!/usr/local/bin/lua

-- io.write()
-- 该函数可以将任意数量的字符串(或者数字)写入到输出流中
-- io.write(args)是io.output():write(args)的简写,即函数write使用在当前输出流上的
-- 格式如下:参数为任意数量,所有的内容会拼接在一起输出
-- io.write(a, b, c...)
-- 与print的区别:
-- print应该用在“用后即弃”或者调试代码中；并且；当需要完全控制输出时,应该使用io.write
-- print会在输出的内容后面默认添加注入制表符或者换行符这样的额外内容；io.write不会在输出内容后面添加任何额外的内容
-- print只能使用标准输出；io.write可以重定向到别的输出流中(例如到文件)
-- print会自动为其参数调用tostring,这一点对于调试非常便利,但也容易导致一些诡异的bug
-- io.write()在将数值转换为字符串时遵循一般的转换规则；如果想要完全地控制这种转换,应该使用string.format()函数:


io.output("test.txt")
io.write("Hello World\n")
io.write("Hello World\n")
io.write("Hello World\n")

io.write("sin(3) = ", math.sin(3), "\n")
io.write(string.format("sin(3) = %.4f\n", math.sin(3)))

-- io.read()
-- io.read()可以从输入流中读取字符串,其参数决定了要读取的数据
-- "a" 读取整个文件
-- "l" 读取下一行(丢弃换行符)
-- "L" 读取下一行(保留换行符)
-- "n" 读取一个数值
-- "num" 以字符串读取num个字符
-- io.read(args)实际上是io.input():read(args)的简写,即函数read使用在当前输入流上的
-- 如果不带任何参数时,io.read()的行为等同于io.read("l"),也就是读取一行的内容(丢弃换行符))
-- 参数a:io.read("a")可以从当前位置开始读取当前输入文件的全部内容)如果当前位置处于文件的末尾或文件为空,那么该函数返回一个空字符串

-- io.read("l")会读取输入流中的一行(不包括换行符在内)；io.read("L")会读取输入流中的一行(会包括换行符在内)
-- 参数l是io.read()的默认参数
-- 当达到文件末尾时,由于已经没有内容可以返回,该函数会返回nil
-- for count = 1,math.huge do
--     local line = io.read("L")
--     if line == nil then
--         break
--     end
--     io.write(string.format("%6d ",count),line)
-- end

-- io.lines():如果想要逐行迭代一个文件,使用io.lines()迭代器会更简单:

-- local count = 0
-- for line in io.lines() do
--     count = count + 1
--     io.write(string.format("%6d ",count),line,"\n")
-- end

io.input("file.txt")

-- local lines = {}
-- for line in io.lines() do
--     lines[#lines + 1] = line
-- end

-- table.sort(lines)

-- for _,line in pairs(lines) do
--     io.write(line,"\n")
-- end

-- while true do
--     local block = io.read(2^13)  -- 块的大小是8KB
--     if not block then 
--         break
--     end
--     io.write(block)
-- end
-- io.read("n")会从当前输入流中读取一个数值)如果在跳过了空格后,函数io.read()仍然不能从当前位置读取到数值(由于错误的格式问题或到了文件末尾),则返回nil

-- io.read(0)是一个特例,它常用于检测是否到达了文件末尾)如果仍然有数据可供读取,它会返回一个空字符串；否则,返回nil

-- 现在有一个文件,每一行由3个数字组成
-- 如果想打印每一行的最大值,可以通过调用下面的代码来一次性地同时读取每行中的3个数字:
-- while true do
--     local n1,n2,n3 = io.read("n","n","n")
--     if not n1 then
--         break
--     end
--     print(math.max(n1,n2,n3))
-- end


-- io.open()
-- io.open()用来打开一个文件,该函数仿造了C语言中的fopen()函数
-- 这个函数有两个参数:
-- 参数1:打开的文件名
-- 参数2:文件打开模式,与C语言类似,r表示只读,w表示只写(同时删除源文件的所有内容)、a表示追加、b表示以二进制的形式打开文件
-- 返回值:
-- 正确:返回打开文件的文件流
-- 失败:返回nil,同时返回一条错误消息以及一个系统相关的错误码

-- 检查错误的一种典型方法是使用函数assert()
-- 如果io.open()执行失败,错误信息会作为函数assert()的第二个参数被传入,之后函数assert()会将错误信息展示出来
-- local f = assert(io.open(filename, mode))

-- read()、write()
-- 当使用io.open()打开文件之后,我们就可以使用read()和write()来读写流,与C语言的read()和write()类似
-- 例如,下面打开一个文件读取其中的所有内容

-- local f = io.open("file.txt","r")
-- if not f then
--     error("open text.txt failed" .. err)
-- end

-- content = f:read("a")
-- io.write(content)

-- I/O库提供了3个预定义的C语言流的句柄:io.stdin、io.stdout、io.stderr
-- 例如,可以使用下面的代码将信息直接写到标准错误流中
-- io.stderr:write("Error", "\n")

-- io.tmpfile()
-- 该函数返回一个操作临时文件的句柄,该句柄是以读/写模式打开的
-- 当程序运行结束后,该临时文件会被自动移除(删除)

-- flush()
-- 函数flush将所有缓冲数据写入文件
-- 与函数write类似,我们也可以把它当做io.flush()使用,以刷新当前输出流
-- 或者把它当做方法f:flush()使用,以刷新流f

-- seek()
-- 该函数用来获取和设置文件的当前位置,常常使用f:seek(whence, offset)的形式来调用
-- 函数参数:
-- whence参数:该参数是一个指定如何使用偏移的字符串,可以设置的值如下
-- set:表示相对于文件开头的偏移,以字节为单位
-- cur:表示相对于文件当前位置的偏移,以字节为单位
-- end:表示相对于文件尾部的偏移,以字节为单位

-- offset参数:根据参数whence,设置偏移值
-- 返回值:返回当前新位置在流中相对于文件开头的偏移
-- whence的默认值为"cur",offset的默认值为0)因此:
-- 调用f:seek():不以任何参数调用该函数,该函数返回流在文件中的当前位置
-- 调用f:seek("set"):会将位置重置到文件开头并返回0
-- 调用f:seek("end"):会将位置重置到文件结尾并返回文件的大小
-- 下面是一些演示案例:
-- function fsize(file)
--     local current = file:seek()    -- 保存当前流偏移位置
--     local size = file:seek("end")  -- 获取文件大小
--     file:seek("set", current)      -- 恢复当前位置
--     return size
-- end

-- os.getenv()
-- 该函数用于获取某个环境变量
-- 该函数的参数是环境变量的名称,返回值是保存了该环境变量对应值的字符串
print(os.getenv("HOME"))

-- os.rename()
-- 该函数用于文件重命名
-- os.remove()
-- 该函数用于移除(删除)文件
-- os.exit()
-- 该函数用于终止程序的执行

-- os.exectue()
-- 该函数用于运行系统命令,它等价于C语言中的system()函数
-- 参数:表示待执行命令的字符串
-- 该函数会返回3个返回值:
-- 返回值1:是一个布尔类型)返回true时表示程序运行成功
-- 返回值2:是一个字符串)当为"exit"时表示程序正常运行结束,当为"signal"时表示因信号而中断
-- 返回值3:是返回状态(若该程序正常终结)或者终结该程序的信号代码
function createDir(dirname)
    os.execute("mkdir " .. dirname)
end

createDir("text")